﻿//--------------------------------------------------------------------------------------------------------------------------------------------------------
// <copyright file="ForgottenPasswordSteps.cs">
//     Copyright © 2010 Oli Francis
//     This source code is subject to the terms and conditions of the MIT license. A copy of the license can be found in the license.txt 
//     file at the root of this distribution. By using this source code in any fashion, you are agreeing to be bound by the terms of the MIT License. 
//     You must not remove this notice from the software.
// </copyright>
// <author>Oli</author>
//-------------------------------------------------------------------------------------------------------------------------------------------------------

namespace TeamBrain.Tests.StepDefinitions
{
    #region Using Statements

    using System;
    using System.Web.Mvc;

    using Moq;

    using NUnit.Framework;

    using TeamBrain.Domain.Services.Exceptions;
    using TeamBrain.Domain.Services.Security;
    using TeamBrain.Tests.Utilities;
    using TeamBrain.Web.Controllers;

    using TechTalk.SpecFlow;

    #endregion

    [Binding]
    [StepScope(Feature = "Forgotten Password")]
    public class ForgottenPasswordSteps
    {
        #region Private fields

        private readonly Mock<ISecurityService> securityService = new Mock<ISecurityService>();
        private SecurityController controller;
        private ActionResult result;

        #endregion

        #region SetUp

        [BeforeScenario]
        public void BeforeScenario()
        {
            ScenarioContext.Current["Email"] = String.Empty;
            this.controller = new SecurityController(this.securityService.Object);
        }

        #endregion

        #region Given

        [Given(@"I enter a valid email address")]
        public void GivenIEnterAValidEmailAddress()
        {
            ScenarioContext.Current["Email"] = "oli@addressexists.com";
        }

        [Given(@"I enter an email address that is not recognised")]
        public void GivenIEnterAnEmailAddressThatIsNotRecognised()
        {
            this.securityService
                .Setup(s => s.RequestPasswordReset(It.IsAny<string>()))
                .Throws(new EmailAddressNotRecognisedException());
        }

        [Given(@"I have a forgotten password email")]
        public void GivenIHaveAForgottenPasswordEmail()
        {
        }

        [Given(@"less than 24 hours have elapsed since the email was sent")]
        public void GivenLessThan24HoursHaveElapsedSinceTheEmailWasSent()
        {
            this.securityService
                .Setup(s => s.CheckPasswordResetToken(It.IsAny<string>()))
                .Returns(TokenStatus.Valid);
        }

        [Given(@"more than 24 hours have elapsed since the email was sent")]
        public void GivenMoreThan24HoursHaveElapsedSinceTheEmailWasSent()
        {
            this.securityService
                .Setup(s => s.CheckPasswordResetToken(It.IsAny<string>()))
                .Returns(TokenStatus.Expired);
        }

        [Given(@"I copy the password reset link from the email")]
        public void GivenICopyThePasswordResetLinkFromTheEmail()
        {
        }

        [Given(@"I make a mistake and don't copy all of the characters")]
        public void GivenIMakeAMistakeAndDontCopyAllOfTheCharacters()
        {
            this.securityService
                .Setup(s => s.CheckPasswordResetToken(It.IsAny<string>()))
                .Returns(TokenStatus.NotRecognised);
        }

        #endregion

        #region When

        [When(@"I follow the password reset link in the email")]
        public void WhenIFollowThePasswordResetLinkInTheEmail()
        {
            var controller = new SecurityController(securityService.Object);
            this.result = controller.ResetPassword("tokenfromemail");
        }

        [When(@"I hit the proceed button")]
        public void WhenIHitTheProceedButton()
        {
            var password = (string)ScenarioContext.Current["Password"];
            this.result = this.controller.ForgottenPassword(password);
        }

        [When(@"I click on the forgot password link at sign-in")]
        public void WhenIClickOnTheForgotPasswordLinkAtSign_In()
        {
            this.result = this.controller.ForgottenPassword();
        }

        [When(@"I paste the url into a browser")]
        public void WhenIPasteTheUrlIntoABrowser()
        {
            var controller = new SecurityController(securityService.Object);
            this.result = controller.ResetPassword("tokenfromemail");
        }

        #endregion

        #region Then

        [Then(@"I see a page asking me to enter my email address")]
        public void ThenISeeAPageAskingMeToEnterMyEmailAddress()
        {
            var view = this.result as ViewResult;
            Assert.IsNotNull(view);
            Assert.AreEqual("ForgottenPassword", view.ViewName);
        }

        [Then(@"a forgotten password email is sent to the address I entered")]
        public void ThenAForgottenPasswordEmailIsSentToTheAddressIEntered()
        {
            this.securityService.Verify(s => s.RequestPasswordReset(It.IsAny<string>()));
        }

        [Then(@"I see a confirmation page")]
        public void ThenISeeAConfirmationPage()
        {
            var redirect = this.result as RedirectToRouteResult;
            Assert.IsNotNull(redirect);
            Assert.AreEqual("ForgottenPasswordEmailSent", redirect.RouteValues["Action"]);
        }

        [Then(@"I see an error message saying that my email address is not valid")]
        public void ThenISeeAnErrorMessageSayingThatMyEmailAddressIsNotValid()
        {
            var view = this.result as ViewResult;
            Assert.IsNotNull(view);
            Assert.IsFalse(view.ViewData.ModelState.IsValidField("email"));
        }

        [Then(@"I see a page allowing me to enter a new password")]
        public void ThenISeeAPageAllowingMeToEnterANewPassword()
        {
            var view = this.result as ViewResult;
            Assert.IsNotNull(view);
            Assert.AreEqual("ResetPassword", view.ViewName);
        }

        [Then(@"I am taken to a page explaining my request has expired")]
        public void ThenIAmTakenToAPageExplainingMyRequestHasExpired()
        {
            var redirect = this.result as RedirectToRouteResult;
            Assert.IsNotNull(redirect);
            Assert.AreEqual("PasswordResetExpired", redirect.RouteValues["Action"]);
        }

        [Then(@"I see a page explaining that the request is not recognised")]
        public void ThenISeeAPageExplainingThatTheRequestIsNotRecognised()
        {
            var redirect = this.result as RedirectToRouteResult;
            Assert.IsNotNull(redirect);
            Assert.AreEqual("PasswordResetInvalid", redirect.RouteValues["Action"]);
        }

        [Then(@"I see a validation error against (.*)")]
        public void ThenISeeAValidationErrorAgainstX(string field)
        {
            var view = this.result as ViewResult;
            Assert.IsNotNull(view);
            Assert.AreEqual("ForgottenPassword", view.ViewName);
            Assert.IsFalse(view.ViewData.ModelState.IsValidField(field.ToPascalCase()));
        }

        #endregion
    }
}
